package com.hzy.chinese.jchess.ui.activity;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.avos.avoscloud.AVException;
import com.avos.avoscloud.AVObject;
import com.avos.avoscloud.AVQuery;
import com.avos.avoscloud.AVUser;
import com.avos.avoscloud.FindCallback;
import com.avos.avoscloud.GetCallback;
import com.blankj.utilcode.util.SnackbarUtils;
import com.blankj.utilcode.util.StringUtils;
import com.github.zackratos.ultimatebar.UltimateBar;
import com.hzy.chinese.jchess.R;
import com.hzy.chinese.jchess.game.GameConfig;
import com.hzy.chinese.jchess.game.GameLogic;
import com.hzy.chinese.jchess.game.GameResult;
import com.hzy.chinese.jchess.game.IGameCallback;
import com.hzy.chinese.jchess.ui.view.GameBoardView;
import com.hzy.chinese.jchess.utils.DbUtil;
import com.hzy.chinese.jchess.utils.KeySet;

import java.util.LinkedList;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;

public class MainActivity extends AppCompatActivity
        implements IGameCallback, NavigationView.OnNavigationItemSelectedListener {

    @BindView(R.id.game_board)
    GameBoardView mGameBoard;
    @BindView(R.id.game_progress)
    ProgressBar mGameProgress;
    @BindView(R.id.toolbar)
    Toolbar toolbar;
    @BindView(R.id.drawlayout)
    DrawerLayout drawerLayout;
    @BindView(R.id.sidebar)
    NavigationView sidebar;

    ImageView iv_headimg;
    TextView tv_score;
    TextView tv_username;

    private SoundPool mSoundPool;
    private LinkedList<Integer> mSoundList;
    private GameLogic mGameLogic;
    private SharedPreferences mPreference;
    private boolean mSoundEnable;
    private int mHandicapIndex;
    private boolean mComputerFlip;
    private int mPieceStyle;
    private int mAILevel;
    private String mPersonInfoObjectId = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initUi();
        mPreference = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        loadDefaultConfig();
        initSoundPool();
        initGameLogic();
        bindData();
    }

    private void initUi() {
        ButterKnife.bind(this);
        View head = sidebar.getHeaderView(0);
        iv_headimg = head.findViewById(R.id.iv_headimg);
        tv_score = head.findViewById(R.id.tv_score);
        tv_username = head.findViewById(R.id.tv_username);
        UltimateBar.newDrawerBuilder().build(this).apply();
        setSupportActionBar(toolbar);
        ActionBar actionbar = getSupportActionBar();
        if(actionbar != null){
            actionbar.setDisplayHomeAsUpEnabled(true);
            actionbar.setHomeAsUpIndicator(R.drawable.ic_toolbar_menu);
        }
        sidebar.setNavigationItemSelectedListener(this);
    }

    private void bindData() {
        AVUser user = AVUser.getCurrentUser();
        String username = user.getUsername();
        tv_username.setText(username);
        if(mPersonInfoObjectId == null){
            AVQuery query = new AVQuery(DbUtil.PERSON_INFO.TABLE_NAME);
            query.whereEqualTo(DbUtil.PERSON_INFO.KEY_USER_ID, user);
            query.findInBackground(new FindCallback<AVObject>() {
                @Override
                public void done(List<AVObject> list, AVException e) {
                    if(e == null){
                        AVObject object = list.size() == 0 ? null : list.get(0);
                        if(object != null){
                            mPersonInfoObjectId = object.getObjectId();
                            int socre = object.getInt(DbUtil.PERSON_INFO.KEY_SCORE);
                            tv_score.setText(String.format(getResources().getString(R.string.power), socre));
                        }
                    }else{
                        tv_score.setText(String.format(getResources().getString(R.string.power), 0));
                    }
                }
            });
        }else{
            AVObject object = AVObject.createWithoutData(DbUtil.PERSON_INFO.TABLE_NAME, mPersonInfoObjectId);
            object.fetchInBackground(DbUtil.PERSON_INFO.KEY_SCORE, new GetCallback<AVObject>() {
                @Override
                public void done(AVObject avObject, AVException e) {
                    if(e == null){
                        int socre = avObject.getInt(DbUtil.PERSON_INFO.KEY_SCORE);
                        tv_score.setText(String.format(getResources().getString(R.string.power), socre));
                    }else{
                        tv_score.setText(String.format(getResources().getString(R.string.power), 0));
                    }
                }
            });
        }

    }


    @Override
    protected void onResume() {
        super.onResume();
        loadDefaultConfig();
        mGameLogic.setLevel(mAILevel);
        mGameBoard.setPieceTheme(mPieceStyle);
        mGameBoard.invalidate();
    }

    @Override
    protected void onDestroy() {
        if (mSoundPool != null) {
            mSoundPool.release();
        }
        mPreference.edit().putString(GameConfig.PREF_LAST_FEN, mGameLogic.getCurrentFen()).apply();
        super.onDestroy();
    }


    private void loadDefaultConfig() {
        mSoundEnable = mPreference.getBoolean(getString(R.string.pref_sound_key), true);
        mHandicapIndex = Integer.parseInt(mPreference.getString(getString(R.string.pref_handicap_key), "0"));
        mComputerFlip = mPreference.getBoolean(getString(R.string.pref_who_first_key), false);
        mPieceStyle = Integer.parseInt(mPreference.getString(getString(R.string.pref_piece_style_key), "0"));
        mAILevel = Integer.parseInt(mPreference.getString(getString(R.string.pref_level_key), "0"));
    }

    private void initSoundPool() {
        mSoundList = new LinkedList<>();
        int poolSize = GameConfig.SOUND_RES_ARRAY.length;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mSoundPool = new SoundPool.Builder().setMaxStreams(poolSize).build();
        } else {
            mSoundPool = new SoundPool(poolSize, AudioManager.STREAM_MUSIC, 0);
        }
        for (int res : GameConfig.SOUND_RES_ARRAY) {
            mSoundList.add(mSoundPool.load(this, res, 1));
        }
    }

    private void initGameLogic() {
        mGameLogic = mGameBoard.getGameLogic();
        mGameLogic.setCallback(this);
        mGameLogic.setLevel(mAILevel);
        mGameBoard.setPieceTheme(mPieceStyle);
        String lastFen = mPreference.getString(GameConfig.PREF_LAST_FEN, "");
        if (StringUtils.isEmpty(lastFen)
                || KeySet.Intent.KEY_GAME_RESTART.equals(getIntent().getStringExtra(KeySet.Intent.KEY_GAME_CMD))) {
            mGameLogic.restart(mComputerFlip, mHandicapIndex);
        } else {
            showMessage(getString(R.string.load_last_game_finish));
            mGameLogic.restart(mComputerFlip, lastFen);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main_toolbar, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:{
                if(!drawerLayout.isDrawerOpen(Gravity.START)){
                    drawerLayout.openDrawer(Gravity.START);
                }
            } break;
            case R.id.main_menu_retract: {
                mGameLogic.retract();
            } break;
            case R.id.main_menu_restart: {
                mGameLogic.restart(mComputerFlip, mHandicapIndex);
                showMessage(getString(R.string.new_game_started));
            } break;

            default:

        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        drawerLayout.closeDrawer(Gravity.START);
        switch (item.getItemId()){
            case R.id.main_menu_settings: {
                startActivity(new Intent(this, SettingsActivity.class));
            } break;
            case R.id.main_menu_person:{
                startActivity(new Intent(this, PersonActivity.class));
            } break;
            case R.id.main_menu_about:{
                startActivity(new Intent(this, SettingsActivity.class));
            } break;
            case R.id.main_menu_logout: {
                LoginActivity.logout(this);
                mPersonInfoObjectId = null;
                finish();
            } break;
            case R.id.main_menu_exit:{
                finish();
            } break;
            default:
        }
        return false;
    }




    @Override
    public void postPlaySound(final int soundIndex) {
        if (mSoundPool != null && mSoundEnable) {
            int soundId = mSoundList.get(soundIndex);
            mSoundPool.play(soundId, 1, 1, 0, 0, 1);
        }
    }

    @Override
    public void postShowMessage(final String message) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                showMessage(message);
            }
        });
    }

    private void showMessage(String message) {
        SnackbarUtils.with(mGameBoard).setDuration(SnackbarUtils.LENGTH_LONG)
                .setMessage(message).show();
    }

    @Override
    public void postShowMessage(int messageId) {
        postShowMessage(getString(messageId));
    }

    @Override
    public void postStartThink() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mGameProgress.setVisibility(View.VISIBLE);
            }
        });
    }

    @Override
    public void postEndThink() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mGameProgress.setVisibility(View.GONE);
            }
        });
    }

    @SuppressLint("CheckResult")
    @Override
    public void postResult(GameResult result) {
        switch (result){
            case WIN:{
                Observable.create(new ObservableOnSubscribe<Integer>() {
                    @Override
                    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                        AVObject object = AVObject.createWithoutData(DbUtil.PERSON_INFO.TABLE_NAME, mPersonInfoObjectId);
                        object.fetch(DbUtil.PERSON_INFO.KEY_SCORE);
                        int score = object.getInt(DbUtil.PERSON_INFO.KEY_SCORE);
                        int newScore = score+mAILevel+1;
                        object.put(DbUtil.PERSON_INFO.KEY_SCORE, newScore);
                        object.save();
                        emitter.onNext(newScore);
                    }
                }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        bindData();
                    }
                });
            } break;
            case LOSE:{
                Observable.create(new ObservableOnSubscribe<Integer>() {
                    @Override
                    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                        AVObject object = AVObject.createWithoutData(DbUtil.PERSON_INFO.TABLE_NAME, mPersonInfoObjectId);
                        object.fetch(DbUtil.PERSON_INFO.KEY_SCORE);
                        int score = object.getInt(DbUtil.PERSON_INFO.KEY_SCORE);
                        int newScore = score+(mAILevel-5);
                        object.put(DbUtil.PERSON_INFO.KEY_SCORE,newScore);
                        object.save();
                        emitter.onNext(newScore);
                    }
                }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Consumer<Integer>() {
                            @Override
                            public void accept(Integer integer) throws Exception {
                                bindData();
                            }
                        });
            } break;
            case DRAW:{

            }
        }

    }


}
